<template>
  <div class="role-container">
    <div class="left-wrapper">
      <!--  知识点：选中高亮的写法,使用索引 -->
      <div
        v-for="(item, index) in roleList"
        :key="item.roleId"
        class="role-item"
        :class="{ active: selectedIndex === index }"
        @click="selectedRole(index, item.roleId)"
      >
        <div class="role-info">
          <svg-icon
            :icon-class="selectedIndex === index ? 'user-active' : 'user'"
            class="icon"
          />
          {{ item.roleName }}
        </div>
        <div class="more">
          <!--  -->
          <el-dropdown
            v-if="hasDropDownItem"
            placement="bottom-start"
            trigger="click"
          >
            <span class="el-dropdown-link">
              <svg-icon icon-class="more" />
            </span>
            <el-dropdown-menu slot="dropdown">
              <el-dropdown-item
                v-permission="'sys:role:add_edit'"
                @click.native="
                  $router.push(`/sys/addRole?roleId=${item.roleId}`)
                "
                >编辑角色</el-dropdown-item
              >
              <el-dropdown-item
                v-permission="'sys:role:remove'"
                @click.native="deleteRole(item.roleId)"
                >删除</el-dropdown-item
              >
            </el-dropdown-menu>
          </el-dropdown>
        </div>
      </div>
      <el-button
        class="addBtn"
        size="mini"
        @click="$router.push('/sys/addRole')"
        >添加角色</el-button
      >
    </div>

    <div class="right-wrapper">
      <!-- tabs -->
      <el-tabs v-model="activeName">
        <el-tab-pane label="功能权限" name="first">
          <!-- 用户管理 tree -->
          <div class="tree-wrapper">
            <div v-for="item in treeList" :key="item.id" class="tree-item">
              <div class="tree-title">{{ item.title }}</div>
              <!-- 知识点：el-tree的 node-key 属性值就是一个字符串，它的值取决于item的属性名-->
              <!-- 知识点：el-tree的check-strictly 控制复选框展示父子是否关联，如果需要控制父子关系，需要设置它
               如果不设置它为true，当你只勾选了父节点，没有勾选子节点，此时回显不了父节点的勾选情况 
          -->
              <el-tree
                check-strictly
                default-expand-all
                ref="tree"
                node-key="id"
                :data="item.children"
                :props="defaultProps"
                show-checkbox
              />
            </div>
          </div>
        </el-tab-pane>
        <el-tab-pane :label="`成员（${totalUser}）`" name="second">
          <!-- 成员 -->
          <div class="user-wrapper">
            <el-table :data="roleUserList" style="width: 100%">
              <el-table-column type="index" width="250" label="序号" />
              <el-table-column prop="name" label="员工姓名" />
              <el-table-column prop="userName" label="登录账号" />
            </el-table>
          </div>
        </el-tab-pane>
      </el-tabs>
    </div>
  </div>
</template>

<script>
import {
  getRoleListAPI,
  getTreeListAPI,
  getRoleDetailByUserAPI,
  getRoleUserAPI,
  delRoleUserAPI
} from '@/api/system'
export default {
  name: 'Role',
  data () {
    return {
      roleList: [],
      treeList: [],
      selectedIndex: 0,
      //修改el-tree默认字段，注意可以直接写在元素里面，而不是必要写到data里
      defaultProps: {
        label: 'title'
        // 知识点：el-tree设置复选框不可用的方式，该方式官方文档没写明确
        // 1.全部都设置为不可操作状态，只需要函数返回teue即可： () => true
        // 2.需要精准控制某一个复选框，可以写一个具名回调函数，在里面写逻辑，详情看下面的disabledCheckbox方法
        // 3.也可以使用递归实现，本质上给data数据加上一个disabled属性值就能控制，我们可以利用递归给需要的对象加上该属性, 如下面的disabledCheckboxRecurve方法
        // disabled: () => true
      },
      activeName: 'first',
      roleUserList: [],
      totalUser: 0
    }
  },
  methods: {
    //删除角色
    deleteRole (roleId) {
      this.$confirm('确认要删除该角色吗', '提示')
        .then(async () => {
          await delRoleUserAPI(roleId)
          this.$message.success('删除成功')
          this.getRoleList()
        })
        .catch(() => {})
    },

    //使用递归控制节点不可编辑
    disabledCheckboxRecurve (list) {
      list.forEach(item => {
        item.disabled = true
        if (item.children) {
          this.disabledCheckboxRecurve(item.children)
        }
      })
    },
    //控制楼宇管理和它的子节点不可编辑（参数1：树节点的值，参数2：当前节点的状态对象）,供参考
    disabledCheckbox (data, node) {
      const disabledList = ['楼宇管理', '添加/编辑楼宇', '删除楼宇']
      if (disabledList.includes(data.title)) {
        return true
      }
    },
    //获取权限树
    async getTreeList () {
      const { data } = await getTreeListAPI()
      this.treeList = data

      this.disabledCheckboxRecurve(this.treeList)
    },

    async selectedRole (index, roleId) {
      // 选中角色高亮设置
      this.selectedIndex = index
      this.echoPermission(roleId)
      //获取对应角色下的用户
      const { data } = await getRoleUserAPI(roleId)
      this.roleUserList = data.rows
      this.totalUser = data.total
    },
    // 角色权限树信息回显
    async echoPermission (roleId) {
      const { data } = await getRoleDetailByUserAPI(roleId)
      // console.log(data.perms)
      // 知识点：el-tree是通过v-for循环遍历出来的，所以根据el-tree的ref去获取元素会获取到多个，需要遍历针对每一个元素进行处理
      const trees = this.$refs.tree
      trees.forEach((item, index) => {
        // 和后端约定好数据格式，比如返回的权限列表数组的顺序和界面的展示索引顺序一样
        item.setCheckedKeys(data.perms[index])
      })
    },
    async getRoleList () {
      const { data } = await getRoleListAPI()
      this.roleList = data
    }
  },
  async created () {
    // 知识点：下面这两个方法都是加了async的异步方法（里面有异步操作），async+await只能保证函数内部是同步执行，但是外面使用该函数的时候
    // 还是属于异步函数，所以，在外部调用异步方法的时候，也需要加async+await确保是同步代码
    await this.getRoleList()
    await this.getTreeList()

    // 知识点：默认回显第一个，调用一下点击事件即可
    if (this.roleList) {
      this.selectedRole(0, this.roleList[0].roleId)
    }
  },
  computed: {
    // 是否展示drowDown
    hasDropDownItem () {
      // 检查是否有权限显示"编辑"或"删除"按钮
      const permissions = this.$store.state.user.permissions
      const hasEdit = permissions.includes('sys:role:add_edit')
      const hasDelete = permissions.includes('sys:role:remove')

      return hasEdit || hasDelete // 只要有一个权限就显示下拉菜单
    }
  }
}
</script>

<style scoped lang="scss">
.role-container {
  display: flex;
  font-size: 14px;
  background-color: #fff;
  padding: 5px;
  .left-wrapper {
    flex-shrink: 0;
    width: 200px;
    border-right: 1px solid #e4e7ec;
    padding: 4px;
    text-align: center;

    .role-item {
      position: relative;
      height: 56px;
      display: flex;
      align-items: center;
      justify-content: space-between;
      padding: 0 20px;
      cursor: pointer;

      &.active {
        background: #edf5ff;
        color: #4770ff;
      }

      .icon {
        font-size: 17px;
      }
    }

    .role-info {
      display: flex;
      align-items: center;

      .icon {
        margin-right: 10px;
      }
    }

    .more {
      display: flex;
      align-items: center;
    }
    .addBtn {
      width: 100%;
      margin-top: 20px;
    }
  }

  .right-wrapper {
    flex: 1;

    .tree-wrapper {
      display: flex;
      justify-content: space-between;

      .tree-item {
        flex: 1;
        border-right: 1px solid #e4e7ec;
        padding: 0px 4px;
        text-align: center;
        .tree-title {
          background: #f5f7fa;
          text-align: center;
          padding: 10px 0;
          margin-bottom: 12px;
        }
      }
    }
    // 知识点：::v-deep 只能穿透直接子组件的 DOM，如果元素在更深层的嵌套组件中，可能需要改用全局样式
    ::v-deep .el-tabs__nav-wrap {
      padding-left: 20px;
    }

    .user-wrapper {
      padding: 20px;
    }

    ::v-deep body .app-main {
      padding: 5px 5px !important;
    }
  }
}
</style>
